package com.macro.mall.tiny.modules.oms.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.macro.mall.tiny.component.wx.entity.bo.WxBO;
import com.macro.mall.tiny.component.wx.entity.bo.WxPayBO;
import com.macro.mall.tiny.modules.oms.mapper.OmsGoodMapper;
import com.macro.mall.tiny.modules.oms.model.OmsGood;
import com.macro.mall.tiny.modules.oms.model.OmsMemberBalanceLog;
import com.macro.mall.tiny.modules.oms.model.OmsOrder;
import com.macro.mall.tiny.modules.oms.mapper.OmsOrderMapper;
import com.macro.mall.tiny.modules.oms.model.OmsPromoCode;
import com.macro.mall.tiny.modules.oms.model.constant.OrderStatusEnum;
import com.macro.mall.tiny.modules.oms.model.dto.CreateOmsOrderDTO;
import com.macro.mall.tiny.modules.oms.service.OmsGoodService;
import com.macro.mall.tiny.modules.oms.service.OmsMemberBalanceLogService;
import com.macro.mall.tiny.modules.oms.service.OmsOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.macro.mall.tiny.modules.oms.service.OmsPromoCodeService;
import com.macro.mall.tiny.modules.ums.mapper.UmsMemberMapper;
import com.macro.mall.tiny.modules.ums.model.UmsMember;
import com.macro.mall.tiny.modules.ums.service.UmsMemberCacheService;
import com.macro.mall.tiny.security.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.cache.CachesEndpoint;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author tyrone
 * @since 2024-10-25
 */
@Service
@Slf4j
public class OmsOrderServiceImpl extends ServiceImpl<OmsOrderMapper, OmsOrder> implements OmsOrderService {


    private static final Snowflake snowflake = IdUtil.getSnowflake(1, 1);

    @Autowired
    private OmsGoodService omsGoodService;

    @Autowired
    private OmsPromoCodeService promoCodeService;

    @Autowired
    private OmsOrderMapper omsOrderMapper;

    @Autowired
    private UmsMemberMapper umsMemberMapper;

    @Autowired
    private OmsGoodMapper omsGoodMapper;

    @Autowired
    private UmsMemberCacheService umsMemberCacheService;

    @Autowired
    private OmsMemberBalanceLogService omsMemberBalanceLogService;


    @Override
    @Transactional
    public OmsOrder createOrder(CreateOmsOrderDTO createOmsOrderDTO) throws Exception {
        Map<Integer, OmsGood> vipPlanMap = omsGoodService.list(new QueryWrapper<OmsGood>().in("id", Lists.newArrayList(1, 2, 3)))
                .stream().collect(Collectors.toMap(OmsGood::getId, omsVipPlan -> omsVipPlan));
        OmsOrder omsOrder = new OmsOrder();
        omsOrder.setOrderId(generateOrderId());
        omsOrder.setGoodId(createOmsOrderDTO.getVipPlanId());
        omsOrder.setStatus(OrderStatusEnum.UN_PAY.getCode());
        omsOrder.setCreateTime(new Date());
        omsOrder.setTotalFee(vipPlanMap.get(createOmsOrderDTO.getVipPlanId()).getFee());
        omsOrder.setOpenId(createOmsOrderDTO.getOpenId());
        omsOrder.setPromoCode(createOmsOrderDTO.getPromoCode());
        calculateActualFee(createOmsOrderDTO, omsOrder);
        SpringUtil.getBean(OmsOrderService.class).save(omsOrder);
        return omsOrder;
    }

    private void calculateActualFee(CreateOmsOrderDTO dto, OmsOrder omsOrder) throws Exception {
        OmsGood vipPlan = omsGoodService.getById(dto.getVipPlanId());
        omsOrder.setTotalFee(vipPlan.getFee());
        if (StringUtils.isNotEmpty(dto.getPromoCode())) {
            OmsPromoCode promoCode = promoCodeService.query().eq("promo_code", dto.getPromoCode()).one();
            if (promoCode == null) {
                throw new Exception("优惠码不存在");
            }
            Double promoRebates = promoCode.getPromoRebates();
            Double rate = 100 - promoRebates;
            log.info("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#calculateActualFee dto:{},omsOrder:{},rate:{}", dto, omsOrder, rate);

            Double actualFee = omsOrder.getTotalFee() * rate / 100;
            log.info("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#calculateActualFee dto:{},omsOrder:{},actualFee:{}", dto, omsOrder, actualFee);
            omsOrder.setActualFee(actualFee.intValue());
        } else {
            omsOrder.setActualFee(omsOrder.getTotalFee());
        }
    }

    /**
     * @param payBO
     */
    @Override
    public void handlePayResult(WxPayBO payBO) {
        String tradeState = payBO.getTradeState();
        //置为支付成功
        if ("SUCCESS".equals(tradeState)) {
            handleSuccessPayResult(payBO);
        }
        //置为未支付 不做操作
        else if ("USERPAYING".equals(tradeState) || "NOTPAY".equals(tradeState)) {

        } else {
            handleFailurePayResult(payBO);
            log.error("支付失败");
        }
    }

    /**
     * 处理成功支付结果
     *
     * @param payBO
     */
    @Transactional(rollbackFor = Exception.class)
    public void handleSuccessPayResult(WxPayBO payBO) {
        try {
            String innerOrderNo = payBO.getInnerOrderNo();
            String openId = payBO.getOpenId();
            //处理订单状态
            OmsOrder omsOrder = omsOrderMapper.selectOne(new QueryWrapper<OmsOrder>()
                    .eq("order_id", innerOrderNo)
                    .eq("open_id", openId));
            omsOrder.setPayTime(new Date());
            omsOrder.setStatus(OrderStatusEnum.PAYED.getCode());
            omsOrderMapper.updateById(omsOrder);
            log.info("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#handleSuccessPayResult 订单处理完成:{}", omsOrder);

            //处理会员状态
            OmsGood good = omsGoodMapper.selectOne(new QueryWrapper<OmsGood>().eq("id", omsOrder.getGoodId()));
            UmsMember umsMember = umsMemberMapper.selectOne(new QueryWrapper<UmsMember>().eq("open_id", openId));
            UmsMember updateMember = new UmsMember();
            updateMember.setId(umsMember.getId());
            updateMember.setVip(1);
            if (umsMember.getVipExpireTime() == null) {
                Date expireDate = DateUtil.offsetDay(omsOrder.getPayTime(), good.getDuration()).toJdkDate();
                updateMember.setVipExpireTime(expireDate);
            } else {
                Date expireDate = DateUtil.offsetDay(umsMember.getVipExpireTime(), good.getDuration()).toJdkDate();
                updateMember.setVipExpireTime(expireDate);
            }
            if (good.getDuration()<0){
                updateMember.setVipExpireTime(DateUtil.parseTime("2099-12-31 23:59:59").toJdkDate());
            }
            umsMemberMapper.updateById(updateMember);
            log.info("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#handleSuccessPayResult 用户信息处理完成:{}", updateMember);
            umsMemberCacheService.delMember(umsMember.getId());

            //处理余额问题
            //todo 如果修改返利这里也要注意
            if (StringUtils.isNotEmpty(omsOrder.getPromoCode())) {
                OmsPromoCode promoCode = promoCodeService.query().eq("promo_code", omsOrder.getPromoCode()).one();
                UmsMember benefitMember = umsMemberMapper.selectOne(new QueryWrapper<UmsMember>().eq("open_id", promoCode.getOpenId()));
                UmsMember benefitMemberUpdate = new UmsMember();
                benefitMemberUpdate.setId(benefitMember.getId());
                Integer benefit = calculateRebateFee(omsOrder, promoCode);
                benefitMemberUpdate.setBalance(benefitMember.getBalance() + benefit);
                log.info("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#handleSuccessPayResult 用户:{} 返利收益：{} 分 订单号:{}, 使用优惠码：{} ", benefitMember, benefit, omsOrder.getOrderId(), omsOrder.getPromoCode());
                umsMemberMapper.updateById(benefitMemberUpdate);
                umsMemberCacheService.delMember(benefitMemberUpdate.getId());
                log.info("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#handleSuccessPayResult 用户收益处理完成:{}", benefitMemberUpdate);

                //记录余额变动
                OmsMemberBalanceLog omsMemberBalanceLog = new OmsMemberBalanceLog();
                omsMemberBalanceLog.setMemberId(benefitMember.getId());
                omsMemberBalanceLog.setOpenId(benefitMember.getOpenId());
                omsMemberBalanceLog.setFee(benefit);
                omsMemberBalanceLog.setBalance(benefitMemberUpdate.getBalance());
                omsMemberBalanceLog.setType(0);
                omsMemberBalanceLog.setDescription(buildDescription(omsOrder, promoCode, benefit, benefitMemberUpdate.getBalance()));
                omsMemberBalanceLogService.save(omsMemberBalanceLog);
                log.info("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#handleSuccessPayResult 用户余额变动记录完成:{}", omsMemberBalanceLog);
            }


            log.info("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#handleSuccessPayResult 用户信息缓存处理完成");
            log.info("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#handleSuccessPayResult 订单处理完成 bo:{}", payBO);
        } catch (Exception e) {
            log.error("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#handleSuccessPayResult 异常:", e);
            log.error("com.macro.mall.tiny.modules.oms.service.impl.OmsOrderServiceImpl#handleSuccessPayResult 开始回滚,bo:{}", payBO);
            throw e;
        }

    }

    private String buildDescription(OmsOrder omsOrder, OmsPromoCode promoCode, Integer benefit, Integer balance) {
        return "订单号：" + omsOrder.getOrderId() + " 使用优惠码：" + promoCode.getPromoCode() + " 获得收益：" + benefit + " 分" + " 当前余额：" + balance + " 分";
    }

    /**
     * todo 如果修改返利这里也要注意
     * 计算返利金额 单位分
     *
     * @param omsOrder
     * @param promoCode
     * @return
     */
    private Integer calculateRebateFee(OmsOrder omsOrder, OmsPromoCode promoCode) {
        Double promoRebates = promoCode.getPromoRebates();
        // 利润55分
        return (omsOrder.getActualFee())/2;
    }

    private void handleFailurePayResult(WxPayBO payBO) {
        String innerOrderNo = payBO.getInnerOrderNo();
        String openId = payBO.getOpenId();
        //处理订单状态
        OmsOrder omsOrder = omsOrderMapper.selectOne(new QueryWrapper<OmsOrder>()
                .eq("order_id", innerOrderNo)
                .eq("open_id", openId));
        omsOrder.setPayTime(new Date());
        omsOrder.setStatus(OrderStatusEnum.PAY_FAIL.getCode());
        omsOrderMapper.updateById(omsOrder);
    }


    public static String generateOrderId() {
        return String.valueOf(snowflake.nextId());
    }

    public static void main(String[] args) {
        System.out.println(snowflake.nextIdStr());
        System.out.println(OmsOrderServiceImpl.generateOrderId());
    }

}
